--- import BaseLayout from "../../layouts/BaseLayout.astro"; import { Header } from "../../components/layout/Header"; import { Card, CardContent } from "../../components/ui/card"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { Star, GitFork, BookOpen, Globe, ExternalLink, ArrowLeft, UserPlus, Server, MapPin, Link as LinkIcon, Building, Users, Calendar, Clock } from "lucide-react"; import { verifyToken } from "../../lib/auth"; import { getDb } from "../../lib/db"; import { eq, desc, and, sql, count } from "drizzle-orm"; import { cachedUsers, cachedRepos, follows } from "../../lib/db/schema"; const token = Astro.cookies.get("community_session")?.value; const user = token ? await verifyToken(token) : null; const { username } = Astro.params; const db = getDb() as any; const profile = await db.query.cachedUsers.findFirst({ where: eq(cachedUsers.username, username as string), with: { instance: true }, }).catch(() => null); const repos = await db.query.cachedRepos.findMany({ where: eq(cachedRepos.ownerUsername, username as string), orderBy: [desc(cachedRepos.starCount), desc(cachedRepos.updatedAt)], with: { instance: true }, }).catch(() => []); // Follower/following counts const [followersCount, followingCount] = await Promise.all([ db.select({ count: sql`count(*)` }).from(follows).where(eq(follows.followeeId, username as string)).then((r: any) => r[0]?.count || 0).catch(() => 0), db.select({ count: sql`count(*)` }).from(follows).where(eq(follows.followerId, username as string)).then((r: any) => r[0]?.count || 0).catch(() => 0), ]); let isFollowing = false; if (user) { const followRecord = await db.query.follows.findFirst({ where: and(eq(follows.followerId, user.sub), eq(follows.followeeId, username as string)), }).catch(() => null); isFollowing = !!followRecord; } // Activity heatmap from repo updatedAt (proxy) const matrix = Array(84).fill(0); const now = new Date(); repos.forEach((r: any) => { if (!r.updatedAt) return; const diffDays = Math.floor(Math.abs(now.getTime() - new Date(r.updatedAt).getTime()) / 86400000); if (diffDays < 84) matrix[83 - diffDays] += 1; }); // Aggregate stats const totalStars = repos.reduce((sum: number, r: any) => sum + (r.starCount || 0), 0); const totalForks = repos.reduce((sum: number, r: any) => sum + (r.forkCount || 0), 0); const languages = [...new Set(repos.map((r: any) => r.language).filter(Boolean))]; const langColors: Record = { TypeScript: "#3178c6", JavaScript: "#f1e05a", Python: "#3572A5", Go: "#00ADD8", Rust: "#dea584", Java: "#b07219", "C++": "#f34b7d", C: "#555555", Ruby: "#701516", PHP: "#4F5D95", Swift: "#F05138", Kotlin: "#A97BFF", Dart: "#00B4AB", Shell: "#89e051", HTML: "#e34c26", CSS: "#563d7c", Vue: "#41b883", }; const displayName = profile?.displayName || username; const avatarUrl = profile?.avatarUrl || `https://api.dicebear.com/7.x/initials/svg?seed=${username}`; const instanceUrl = profile?.instance?.url ? `${profile.instance.url}/${username}` : null; ---
Back to Explore
{displayName}

{displayName}

@{username}
{instanceUrl && }

{profile?.bio || "Decentralized developer on the OpenCodeHub federated mesh."}

{profile?.instance?.name && {profile.instance.name}} {profile?.location && {profile.location}} {profile?.company && {profile.company}} {profile?.website && Website}
{repos.length}
Repos
{totalStars}
Stars
{totalForks}
Forks
{followersCount}
Followers
{followingCount}
Following

Repositories ({repos.length})

{repos.length === 0 ? (
No repositories indexed for this profile yet.
) : ( repos.map((repo: any) => { const lc = langColors[repo.language] || "#888"; return (
{repo.name} {repo.visibility || "public"}

{repo.description || "No description provided."}

{repo.language && {repo.language}} {repo.starCount || 0} {repo.forkCount || 0}
{repo.updatedAt && {new Date(repo.updatedAt).toLocaleDateString()}}
); }) )}

ActivityLast 12 weeks

{matrix.map((count) => { const bg = count >= 3 ? "bg-emerald-500" : count === 2 ? "bg-emerald-500/70" : count === 1 ? "bg-emerald-500/40" : "bg-muted/60"; return
; })}
Less
More
{languages.length > 0 && (

Languages

{languages.slice(0, 8).map((lang: string) => (
{lang}
))}
)} {profile?.instance && (

Home Instance

{profile.instance.name}
{profile.instance.siteUrl}
)}